﻿using System;
using System.Threading.Tasks;

namespace Beeflys
{
    delegate Task<bool> FuncAsyncDelegate(AActor actor);
    delegate Task InvokStartDelegate<TStarter>(TStarter starter);


    sealed class ActorStartNotify
    {
        public async Task InvokStartNotifyAsync(IActorRef actorRef)
        {
            await this.InvokeStartAsync<IStart>(actorRef, async (starter) =>
            {
                await starter.StartAsync();
            });
        }

        public async Task InvokStartNotifyAsync<T1>(IActorRef actorRef,
            T1 item1)
        {
            await this.InvokeStartAsync<IStart<T1>>(actorRef, async (starter) =>
            {
                await starter.StartAsync(item1);
            });
        }

        public async Task InvokStartNotifyAsync<T1, T2>(IActorRef actorRef,
            T1 item1, T2 item2)
        {
            await this.InvokeStartAsync<IStart<T1, T2>>(actorRef, async (starter) =>
            {
                await starter.StartAsync(item1, item2);
            });
        }

        public async Task InvokStartNotifyAsync<T1, T2, T3>(IActorRef actorRef,
            T1 item1, T2 item2, T3 item3)
        {
            await this.InvokeStartAsync<IStart<T1, T2, T3>>(actorRef, async (starter) =>
            {
                await starter.StartAsync(item1, item2, item3);
            });
        }

        public async Task InvokStartNotifyAsync<T1, T2, T3, T4>(IActorRef actorRef,
            T1 item1, T2 item2, T3 item3, T4 item4)
        {
            await this.InvokeStartAsync<IStart<T1, T2, T3, T4>>(actorRef, async (starter) =>
            {
                await starter.StartAsync(item1, item2, item3, item4);
            });
        }

        public async Task InvokStartNotifyAsync<T1, T2, T3, T4, T5>(IActorRef actorRef,
            T1 item1, T2 item2, T3 item3, T4 item4, T5 item5)
        {
            await this.InvokeStartAsync<IStart<T1, T2, T3, T4, T5>>(actorRef, async (starter) =>
            {
                await starter.StartAsync(item1, item2, item3, item4, item5);
            });
        }

        public async Task InvokStartNotifyAsync<T1, T2, T3, T4, T5, T6>(IActorRef actorRef,
            T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6)
        {
            await this.InvokeStartAsync<IStart<T1, T2, T3, T4, T5, T6>>(actorRef, async (starter) =>
            {
                await starter.StartAsync(item1, item2, item3, item4, item5, item6);
            });
        }

        public async Task InvokStartNotifyAsync<T1, T2, T3, T4, T5, T6, T7>(IActorRef actorRef,
            T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7)
        {
            await this.InvokeStartAsync<IStart<T1, T2, T3, T4, T5, T6, T7>>(actorRef, async (starter) =>
            {
                await starter.StartAsync(item1, item2, item3, item4, item5, item6, item7);
            });
        }

        private async Task InvokeStartAsync<TStarter>(IActorRef actorRef, InvokStartDelegate<TStarter> invokStartDelegate)
        {
            FuncAsyncDelegate startAsyncNotify = async (actor) =>
            {
                if (actor == null) return false;
                if (actor is TStarter starter)
                {
                    await invokStartDelegate(starter);
                    return true;
                }
                return false;
            };

            var notify = new SystemArgsNotify(startAsyncNotify, SystemNotifyType.START);
            var req = await actorRef.CallAsync<bool>(notify, TimeSpan.Zero, null);
            if (!req.Response)
            {
                if (typeof(TStarter) != typeof(IStart))
                {
                    throw new Exception($"Invoke {typeof(TStarter).Name} fail");
                }
            }
        }
    }
}
